package com.company.cloud.user.modules.app.controller;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.company.cloud.captcha.modules.util.StringUtils;
import com.company.cloud.common.asserts.ValidatorUtils;
import com.company.cloud.common.auth.annotation.Login;
import com.company.cloud.common.bean.BaseResult;
import com.company.cloud.common.bean.LoginSimpleUserInfo;
import com.company.cloud.common.bean.LoginUserInfo;
import com.company.cloud.common.constant.BaseReturnEnum;
import com.company.cloud.common.exception.BusinessException;
import com.company.cloud.common.redis.service.RedisUtils;
import com.company.cloud.common.utils.AuthContextUtils;
import com.company.cloud.common.utils.CheckUtils;
import com.company.cloud.common.utils.EnumUtils;
import com.company.cloud.common.utils.HttpContextUtils;
import com.company.cloud.point.modules.api.request.PointEventParam;
import com.company.cloud.point.modules.api.service.PointRemoteService;
import com.company.cloud.user.constant.ErrorUserEnum;
import com.company.cloud.user.constant.UserMsgSendTypeEnum;
import com.company.cloud.user.modules.api.constant.UserRegisterWayEnum;
import com.company.cloud.user.modules.api.request.UserRegisterParam;
import com.company.cloud.user.modules.app.controller.req.UserLogin2RegByThirdParam;
import com.company.cloud.user.modules.app.controller.req.UserLoginBindWxMobile;
import com.company.cloud.user.modules.app.controller.req.UserLoginByThirdNoRegParam;
import com.company.cloud.user.modules.app.controller.req.UserLoginByThirdParam;
import com.company.cloud.user.modules.app.models.ThirdUserEntity;
import com.company.cloud.user.modules.app.models.User2ThirdModel;
import com.company.cloud.user.modules.app.service.*;
import com.company.cloud.user.modules.base.entity.ThirdUserInfo;
import com.company.cloud.user.modules.base.entity.UserInfo;
import com.company.cloud.user.modules.base.service.ThirdUserInfoService;
import com.company.cloud.user.modules.base.service.UserInfoService;
import com.company.cloud.user.modules.bus.producer.UserProducer;
import com.company.cloud.user.modules.cache.models.UserInvitationModel;
import com.company.cloud.user.modules.cache.service.UserPermissionCacheService;
import com.company.common.server.config.cloud.ProjectConfig;
import com.company.common.server.constant.AppEventEnum;
import com.company.common.server.constant.LoginThirdChannelEnum;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;

/**
 * 三方用户登录
 */
@Log4j2
@RestController
@RequestMapping("/app/user/login")
@Api(tags = "UC_三方用户登录")
public class UserLogin2ThirdController {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private UserLoginService userLoginService;

    @Autowired
    private UserRegisterService userRegisterService;

    @Autowired
    private UserCodeService userCodeService;

    @Autowired
    private UserPermissionCacheService userPermissionCacheService;

    @Autowired
    private ThirdUserInfoService thirdUserInfoService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private UserAppService userAppService;

    @Autowired
    private UserCompanyService userCompanyService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private ProjectConfig projectConfig;

    @Autowired
    private UserProducer userProducer;

    @Autowired
    private ThirdUserApiService thirdUserApiService;

    //todo:del
    @Autowired
    private PointRemoteService pointRemoteService;

    private void setWXSessionKey(String userToken, ThirdUserEntity thirdEntity) {
        if (thirdEntity != null && StrUtil.isNotEmpty(thirdEntity.getSessionKey())) {
            redisUtils.set(userToken + ":wx", thirdEntity.getSessionKey(), 3600 * 71);
        }
    }

    @PostMapping("/loginByThirdNoReg")
    @ApiOperation(value = "(第三方平台用户)登录不注册")
    public BaseResult loginByThirdNoReg(@RequestBody UserLoginByThirdNoRegParam params) {
        ValidatorUtils.validate(params);
        String companyNo = userCompanyService.companyCheck(AuthContextUtils.getCompanyNo());

        LoginThirdChannelEnum channel = EnumUtils.getBaseCodeEnum(LoginThirdChannelEnum.class, params.getThirdChannel());
        ThirdUserEntity thirdEntity = thirdUserApiService.loginThird(channel, companyNo, params.getCode());

        User2ThirdModel user2Third = userLoginService.loginByThird(companyNo, channel, thirdEntity.getOpenId(), HttpContextUtils.getClientIP(), false);
        LoginUserInfo data = userLoginService.login(user2Third.getUser(), user2Third.getThirdUser(), thirdEntity);
        if (data == null) {
            BaseResult result = BaseResult.ok(thirdEntity);
            result.setMsg(ErrorUserEnum.User_Info_Error.getMsg());
            return result;
        }
        userPermissionCacheService.loadPermissionRoleCache(data.getCompanyNo());
        this.setWXSessionKey(data.getToken(), thirdEntity);
        if (StringUtils.isEmpty(data.getMobile())) {
            BaseResult result = BaseResult.ok(thirdEntity);
            result.setMsg(ErrorUserEnum.USER_MOBILE_NULL.getMsg());
            return result;
        }
        userProducer.userLogin("三方平台用户登录", params, data);
        return BaseResult.ok(data);
    }

    @PostMapping("/loginByThird")
    @ApiOperation(value = "(第三方平台用户)登录并注册")
    public BaseResult loginByThird(@RequestBody UserLoginByThirdParam params, HttpServletRequest request) {
        ValidatorUtils.validate(params);

        String mobile = params.getMobile();
        if (StringUtils.isBlank(mobile)) {
            throw new BusinessException(ErrorUserEnum.USER_MOBILE_NULL);
        }

        boolean isReg = false;
        PointEventParam pointEventParam = null;
        String companyNo = userCompanyService.getCompany2Check(AuthContextUtils.getShareCode(), AuthContextUtils.getCompanyNo());
        LoginThirdChannelEnum channel = EnumUtils.getBaseCodeEnum(LoginThirdChannelEnum.class, params.getThirdChannel());
        if (channel == LoginThirdChannelEnum.WxApp_User) {
            userCodeService.validate(companyNo, UserMsgSendTypeEnum.Third_Bind_VCode, params.getMobile(), params.getVcode(), true);
        }

        ThirdUserEntity thirdEntity = new ThirdUserEntity();
        thirdEntity.setOpenId(params.getOpenId());
        //获取Token
        String token = request.getHeader("token");
        System.out.println("++++token : " + token);
        String sessionKey = redisUtils.get(token + ":wx");

        thirdEntity.setSessionKey(sessionKey);
        User2ThirdModel user2Third = userLoginService.loginByThird(companyNo, channel, thirdEntity.getOpenId(), HttpContextUtils.getClientIP(), true);

        String nickname = params.getNickname();
        if (StringUtils.isEmpty(nickname)) {
            nickname = "微信用户";
        }

        String avatar = params.getAvatar();
        if (StringUtils.isEmpty(avatar)) {
            avatar = "https://img.artshanghaifair.com/ui/icon-male.png";
        }

        UserInfo userInfo = userInfoService.getOne(new QueryWrapper<UserInfo>()
                .eq("company_no", companyNo)
                .eq("mobile", mobile)
        );

        if (userInfo == null) {
            userInfo = user2Third.getUser();
        }

        if (userInfo == null) {
            /**
             * 用户注册
             */
            UserRegisterParam registerParam = new UserRegisterParam();
            registerParam.setCompanyNo(companyNo);
            registerParam.setUserName(params.getOpenId());
            registerParam.setReferralCode(AuthContextUtils.getShareCode());
            registerParam.setRegIp(HttpContextUtils.getClientIP());
            registerParam.setRegWay(UserRegisterWayEnum.Reg_UserName.getCode());
            registerParam.setDisFlg(params.getDisFlg());
            registerParam.setMobile(mobile);
            registerParam.setHeadImg(avatar);
            registerParam.setNickName(nickname);
            userInfo = userRegisterService.register(registerParam, null);
            isReg = true;
            pointEventParam = new PointEventParam();
            pointEventParam.setEventNo(AppEventEnum.User_Register.getCode());
        } else {
            /**
             * 更新用户手机号、头像、昵称
             */
            userInfo.setMobile(params.getMobile());
            userInfo.setNickName(nickname);
            userInfo.setHeadImg(avatar);
            userLoginService.updateUserInfo(userInfo);
        }

        // 更新第三方用户的 UserId
        userLoginService.updateThirdUserId(channel, thirdEntity.getOpenId(), userInfo.getId());

        /**
         * 更新登录信息
         */
        LoginUserInfo data = userLoginService.login(userInfo, user2Third.getThirdUser(), thirdEntity);
        userPermissionCacheService.loadPermissionRoleCache(data.getCompanyNo());

        //todo:更改成MQ方式
        if (pointEventParam != null) {
            try {
                pointEventParam.setUserId(userInfo.getId());
                pointEventParam.setCompanyNo(projectConfig.getCompanyNo(userInfo.getCompanyNo()));
                pointEventParam.setOpUserId(userInfo.getId());
                pointEventParam.setOpIp(data.getIp());
                pointRemoteService.pointEventProcess(pointEventParam);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        if (isReg) {
            userProducer.userRegister(UserRegisterWayEnum.Reg_UserName.getCode(), params, params.getDisFlg(), data);
        } else {
            userProducer.userLogin("三方平台用户登录", params, data);
        }

        logger.info("接口loginByThird-用户信息{}", JSON.toJSONString(data));
        return BaseResult.ok(data);
    }

    @Login
    @PostMapping("/loginByThirdBindWxMobile")
    @ApiOperation(value = "(第三方平台用户)自动绑定手机号(微信)")
    public BaseResult loginByThirdBindWxMobile(@RequestBody UserLoginBindWxMobile params) {
        ValidatorUtils.validate(params);
        System.out.println("++++(第三方平台用户)自动绑定手机号(微信)+++ : " + JSON.toJSONString(params));
        LoginSimpleUserInfo loginSimple = AuthContextUtils.getUser();
        System.out.println("+++++++用户信息:" + JSON.toJSONString(loginSimple));
        String thirdSessionKey = redisUtils.get(loginSimple.getToken() + ":wx");
        LoginThirdChannelEnum channel = EnumUtils.getBaseCodeEnum(LoginThirdChannelEnum.class, params.getThirdChannel());
        JSONObject object = thirdUserApiService.decryptData(channel, params.getEncryptedMobile(), params.getIv(), thirdSessionKey);
        String mobile = object.getString("phoneNumber");

        UserInfo userInfoOld = userLoginService.getRegUserById(loginSimple.getId());
        if (CheckUtils.isEmpty(loginSimple.getThirdId())) {
            throw new BusinessException(ErrorUserEnum.User_Third_Not);
        }

        if (!CheckUtils.isEmpty(userInfoOld.getMobile())) {
            throw new BusinessException(ErrorUserEnum.USER_MOBILE_EXISTS);
        }

        // 验证手机号唯一
        UserInfo userInfo = userInfoService.getOne(new QueryWrapper<UserInfo>()
                .eq("company_no", loginSimple.getCompanyNo())
                .eq("mobile", mobile)
        );

        if (null != userInfo) {
            throw new BusinessException(ErrorUserEnum.USER_MOBILE_EXISTS);
        }

        UserInfo userInfoNew = userInfoService.getOne(new QueryWrapper<UserInfo>()
                .eq("company_no", loginSimple.getCompanyNo())
                .eq("mobile", mobile));

        if (userInfoNew == null) {
            userInfoOld.setMobile(mobile);
            userInfoOld.setUserTypeOne(params.getUserTypeOne());
            userInfoOld.addEditParam(loginSimple);
            userInfoService.updateById(userInfoOld);
        } else {
            ThirdUserInfo thirdUser = thirdUserInfoService.getById(loginSimple.getThirdId());
            thirdUser.setUserId(userInfoNew.getId());
            thirdUser.addEditParam(loginSimple);
            thirdUserInfoService.updateById(thirdUser);
        }

        //重新登录
        User2ThirdModel user2Third = userLoginService.loginByThird(userInfoOld.getCompanyNo(),
                EnumUtils.getBaseCodeEnum(LoginThirdChannelEnum.class, params.getThirdChannel()),
                loginSimple.getThirdOpenId(),
                HttpContextUtils.getClientIP(),
                false);

        // 刷新用户缓存
        LoginUserInfo data;
        if (userInfoNew != null) {
            data = userLoginService.login(userInfoNew, user2Third.getThirdUser(), loginSimple.getToken(), null);
        } else {
            data = userLoginService.login(userInfoOld, user2Third.getThirdUser(), loginSimple.getToken(), null);
        }
        userPermissionCacheService.loadPermissionRoleCache(data.getCompanyNo());
        logger.info("接口loginByThirdBindMobile-用户信息{}", JSON.toJSONString(data));
        return BaseResult.ok(data);
    }

    @Login
    @PostMapping("/loginByThirdBindMobile")
    @ApiOperation(value = "(第三方平台用户)绑定手机号")
    public BaseResult loginByThirdBindMobile(@RequestBody UserLogin2RegByThirdParam params) {
        ValidatorUtils.validate(params);
        LoginSimpleUserInfo loginSimple = AuthContextUtils.getUser();
        UserInfo userInfo = userLoginService.getRegUserById(loginSimple.getId());

        if (CheckUtils.isEmpty(loginSimple.getThirdId())) {
            throw new BusinessException(ErrorUserEnum.User_Third_Not);
        }
        if (!CheckUtils.isEmpty(userInfo.getMobile())) {
            throw new BusinessException(ErrorUserEnum.USER_MOBILE_EXISTS);
        }
        userCodeService.validate(loginSimple.getCompanyNo(), UserMsgSendTypeEnum.Login_VCode, params.getMobile(), params.getVcode(), true);

        //验证手机号唯一
        int count = userInfoService.count(new QueryWrapper<UserInfo>()
                .eq("company_no", loginSimple.getCompanyNo())
                .eq("mobile", params.getMobile())
        );
        if (count > 0) {
            throw new BusinessException(ErrorUserEnum.USER_MOBILE_EXISTS);
        }

        userInfo.setMobile(params.getMobile());
        userInfo.setUserTypeOne(params.getUserTypeOne());
        userInfo.addEditParam(loginSimple);
        userInfoService.updateById(userInfo);

        //重新登录
        User2ThirdModel user2Third = userLoginService.loginByThird(
                userInfo.getCompanyNo(),
                EnumUtils.getBaseCodeEnum(LoginThirdChannelEnum.class, params.getThirdChannel()),
                loginSimple.getThirdOpenId(),
                HttpContextUtils.getClientIP(),
                false);

        // 刷新用户缓存
        LoginUserInfo data = userLoginService.login(userInfo, user2Third.getThirdUser(), loginSimple.getToken(), null);
        userPermissionCacheService.loadPermissionRoleCache(data.getCompanyNo());
        logger.info("接口loginByThirdBindMobile-用户信息{}", JSON.toJSONString(data));
        return BaseResult.ok(data);
    }

    @GetMapping("/getPasswordInvitationById")
    @ApiOperation(value = "根据ID获取邀请信息", response = UserInvitationModel.class)
    public BaseResult getPasswordInvitationById(@RequestParam("id") Integer id) {
        if (CheckUtils.isEmpty(id)) {
            throw new BusinessException(BaseReturnEnum.PARAM_ERROR);
        }
        UserInvitationModel data = userAppService.getPasswordInvitationById(id);
        return BaseResult.ok(data);
    }

    @PostMapping("/getBindWxMobile")
    @ApiOperation(value = "(第三方平台用户)获取手机号(微信)")
    public BaseResult getBindWxMobile(@RequestBody UserLoginBindWxMobile params, HttpServletRequest request) {
        System.out.println("++++(第三方平台用户)测试是否有进入到该方法+++ : ");
        ValidatorUtils.validate(params);
        System.out.println("++++(第三方平台用户)获取手机号(微信)+++ : " + JSON.toJSONString(params));
        String thirdSessionKey = params.getSessionKey();
        System.out.println("++++(第三方平台用户)开始获取token+ : " );
        //获取Token
        String token = request.getHeader("token");
        System.out.println("++++token : " + token);
        String sessionKey = redisUtils.get(token + ":wx");
        if (!sessionKey.equals(thirdSessionKey)){
            throw new BusinessException(BaseReturnEnum.NOT_AUTHC);
        }
        LoginThirdChannelEnum channel = EnumUtils.getBaseCodeEnum(LoginThirdChannelEnum.class, params.getThirdChannel());
        JSONObject object = thirdUserApiService.decryptData(channel, params.getEncryptedMobile(), params.getIv(), sessionKey);
        String mobile = object.getString("phoneNumber");
        return BaseResult.ok(mobile);
    }

}
